package com.tmt.im.service.interfaces.impl;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.im.common.Constant;
import com.tmt.im.common.enums.ChatSessionType;
import com.tmt.im.common.vo.NewChatSessionVo;
import com.tmt.im.common.vo.QueryMembersRequest;
import com.tmt.im.common.yunxin.ErrorCode;
import com.tmt.im.common.yunxin.YunXinHelper;
import com.tmt.im.service.config.beans.GroupInitParam;
import com.tmt.im.service.config.beans.YunXinProperties;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.UpdateSessionVoHelper;
import com.tmt.im.service.interfaces.IYunXinInterface;
import org.apache.ignite.Ignite;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/28 10:55
 * @Version 1.0
 **/
@Order(1)
public class YunXinInterfaceImpl_V10 implements IYunXinInterface, ApplicationContextAware {

    private static final String SEND_SYSTEM_NOTIFY_URL = "https://open.yunxinapi.com/im/v2/custom_notification";

    private static final String BATCH_SEND_SYSTEM_NOTIFY_URL = " https://open.yunxinapi.com/im/v2/custom_notification/batch";

    private static final String CREATE_SESSION_URL = "https://open.yunxinapi.com/im/v2/teams";

    private static final String MANAGE_SESSION_URL = "https://open.yunxinapi.com/im/v2/teams/{team_id}";


    private static final String TRANSFER_OWNER_SESSION_URL = "https://open.yunxinapi.com/im/v2/teams/{team_id}/actions/transfer_owner";

    private static final String ADD_MANAGER_URL = "https://open.yunxinapi.com/im/v2/teams/{team_id}/actions/add_manager";

    private static final String REMOVE_MANAGER_URL = "https://open.yunxinapi.com/im/v2/teams/{team_id}/actions/remove_manager";

    private static final String LIST_MEMBERS_URL = "https://open.yunxinapi.com/im/v2/teams/{team_id}/actions/list_members";

    private static final String JOIN_SESSION_URL = "https://open.yunxinapi.com/im/v2/team_members";

    private static final String KICK_OUT_SESSION_URL = "https://open.yunxinapi.com/im/v2/team_members/actions/kick_member";

    private static final String LEAVE_SESSION_URL = "https://open.yunxinapi.com/im/v2/team_members/actions/leave";

    private static final String UPDATE_MEMBER_SETTING_URL = "https://open.yunxinapi.com/im/v2/team_members/{account_id}";

    private static final List<String> MainParams = List.of("operator_id", "team_type", "name", "icon",
            "announcement", "intro", "members_limit", "server_extension", "extension");

    private static final List<String> ConfigParams = List.of("join_mode", "agree_mode", "invite_mode",
            "update_team_info_mode", "update_extension_mode");

    private YunXinProperties yunXinProperties;

    private Ignite ignite;

    @Override
    public JSONObject createSession(Long creatorId, String creatorNick, NewChatSessionVo sessionVo, StringBuilder error) {
        try {
            GroupInitParam initParam = yunXinProperties.getGroupInitParam();

            Map<String, Object> configuration = new LinkedHashMap<>();
            /*通过 SDK 侧操作申请入群的验证方式。
            0（默认）：无需验证，直接入群。
            1：需要群主或管理员验证通过才能入群。
            2：不允许任何人申请入群。*/
            configuration.put("join_mode", initParam.getJoinMode());
            /*邀请入群时是否需要被邀请人的同意。
            0（默认）：需要被邀请人同意才能入群。
            1：不需要被邀请人同意，直接入群。*/
            configuration.put("agree_mode", initParam.getAgreeMode());
            /*邀请权限，即谁可以邀请他人入群。
            0（默认）：群主和管理员。
            1：所有人。*/
            configuration.put("invite_mode", initParam.getInviteMode());
            /*客户端修改群组信息的权限，即谁可以修改群组信息。
            0（默认）：群主和管理员。
            1：所有人。*/
            configuration.put("update_team_info_mode", initParam.getUpdateTeamInfoMode());
            /*客户端修改群自定义扩展信息（server_extension&extension）权限，即谁可以修改群自定义扩展信息。
            0（默认）：群主和管理员。
            1：所有人。*/
            configuration.put("update_extension_mode", initParam.getUpdateExtensionMode());

            String inviteMsg = String.format(initParam.getInviteMsg(), creatorNick);
            if (StringUtils.hasText(sessionVo.getInviteMsg())) {
                inviteMsg = sessionVo.getInviteMsg();
            }

            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("owner_account_id", creatorId);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", 1);
            reqParam.put("name", sessionVo.getName());
            reqParam.put("invite_msg", inviteMsg);
            reqParam.put("invite_account_ids", sessionVo.getInvitedIds());
            reqParam.put("configuration", configuration);

            JSONObject jsonObject = YunXinHelper.exchange(CREATE_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject getSessionDetail(Long tid, StringBuilder error) {
        return null;
    }

    @Override
    public JSONObject getAllInSession(Long creatorId, StringBuilder error) {
        return null;
    }

    public JSONObject getSession(Long operatorId, ChatSessionType type, Long tid, StringBuilder error) {
        String url = MANAGE_SESSION_URL.replace("{team_id}", "" + tid);
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));

            JSONObject jsonObject = YunXinHelper.exchange(url, HttpMethod.GET, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject updateSession(Long operatorId, ChatSessionType type, UpdateSessionRequest request, StringBuilder error) {
        MultiValueMap<String, Object> newParams = UpdateSessionVoHelper.convertTo(operatorId, type, request);
        String url = MANAGE_SESSION_URL.replace("{team_id}", "" + request.getTid());
        try {
            Map<String, Object> configuration = new LinkedHashMap<>();
            for (String configParam : ConfigParams) {
                if (newParams.containsKey(configParam)) {
                    configuration.put(configParam, newParams.get(configParam));
                }
            }

            Map<String, Object> reqParam = new LinkedHashMap<>();
            if (configuration.size() > 0) {
                reqParam.put("configuration", configuration);
            }
            for (String param : MainParams) {
                if (newParams.containsKey(param)) {
                    reqParam.put(param, newParams.get(param));
                }
            }

            JSONObject jsonObject = YunXinHelper.exchange(url, HttpMethod.PATCH, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public boolean deleteSession(Long operatorId, ChatSessionType teamType, Long tid, StringBuilder error) {
        String url = MANAGE_SESSION_URL.replace("{team_id}", "" + tid);
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("operator_id", "" + operatorId);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, teamType.getType()));

            JSONObject jsonObject = YunXinHelper.exchange(url, HttpMethod.DELETE, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean bannedSession(Long operatorId, ChatSessionType type, Long tid, int bannedType, StringBuilder error) {
        return false;
    }

    @Override
    public boolean updateSessionJoinMode(Long tid, Long ownerId, int joinMode, StringBuilder error) {
        return false;
    }

    @Override
    public boolean transferSession(Long operatorId, Long tid, ChatSessionType type, Long newOwnerId, boolean leave, StringBuilder error) {
        String url = TRANSFER_OWNER_SESSION_URL.replace("{team_id}", "" + tid);
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));
            reqParam.put("new_owner_account_id", newOwnerId);
            reqParam.put("leave", leave ? 1 : 2);
            JSONObject jsonObject = YunXinHelper.exchange(url, HttpMethod.PATCH, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L || code == 108310L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean addManager(Long operatorId, Long tid, ChatSessionType type, List<Long> managers, StringBuilder error) {
        String url = ADD_MANAGER_URL.replace("{team_id}", "" + tid);
        return _updateManager(url, HttpMethod.POST, operatorId, type, managers, error);
    }

    @Override
    public boolean removeManager(Long operatorId, Long tid, ChatSessionType type, List<Long> managers, StringBuilder error) {
        String url = REMOVE_MANAGER_URL.replace("{team_id}", "" + tid);
        return _updateManager(url, HttpMethod.DELETE, operatorId, type, managers, error);
    }

    @Override
    public JSONObject queryMembers(Long operatorId, Long tid, ChatSessionType type, QueryMembersRequest request, StringBuilder error) {
        String url = LIST_MEMBERS_URL.replace("{team_id}", "" + tid);
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));
            if (request.getMemberType() != null) {
                reqParam.put("member_type", request.getMemberType());
            }
            if (request.getBannedType() != null) {
                reqParam.put("chat_banned_type", request.getBannedType());
            }
            if (request.getDescending() != null) {
                reqParam.put("descending", request.getDescending());
            }
            if (request.getPageSize() != null) {
                reqParam.put("limit", request.getPageSize());
            }

            JSONObject jsonObject = YunXinHelper.exchange(url, HttpMethod.GET, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject joinSession(Long operatorId, Long tid, ChatSessionType type, int agreeMode, String inviteMsg, List<Long> memberIds, StringBuilder error) {
        try {
            int teamType = Math.max(1, type.getType());
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("operator_id", "" + operatorId);
            reqParam.put("team_id", tid);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", teamType);
            reqParam.put("invite_account_ids", memberIds);
            reqParam.put("msg", inviteMsg);

            JSONObject jsonObject = YunXinHelper.exchange(JOIN_SESSION_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public JSONObject kickOutSession(Long operatorId, Long tid, ChatSessionType type, List<Long> memberIds, StringBuilder error) {
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("operator_id", "" + operatorId);
            reqParam.put("team_id", tid);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));
            reqParam.put("kick_account_ids", memberIds.stream().map(x -> "" + x).collect(Collectors.toList()));

            JSONObject jsonObject = YunXinHelper.exchange(KICK_OUT_SESSION_URL, HttpMethod.DELETE, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public boolean leaveSession(Long operatorId, Long tid, ChatSessionType type, StringBuilder error) {
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("account_id", "" + operatorId);
            reqParam.put("team_id", tid);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));

            JSONObject jsonObject = YunXinHelper.exchange(LEAVE_SESSION_URL, HttpMethod.DELETE, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean updateMemberNick(Long currentUserId, Long tid, ChatSessionType type, UpdateMemberNickRequest request, StringBuilder error) {
        return false;
    }

    @Override
    public JSONObject bannedMembers(Long operatorId, Long tid, ChatSessionType type, ChatBannedRequest request, StringBuilder error) {
        try {
            List<String> strList = new ArrayList<>();
            for (Long memberId : request.getMemberIds()) {
                strList.add("" + memberId);
            }
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("operator_id", "" + operatorId);
            reqParam.put("team_id", tid);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));
            reqParam.put("chat_ban_account_ids", strList);
            reqParam.put("chat_banned", request.getChatBanned());

            JSONObject jsonObject = YunXinHelper.exchange(KICK_OUT_SESSION_URL, HttpMethod.DELETE, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return jsonObject;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return null;
    }

    @Override
    public boolean noDisturbingMember(Long currentUserId, Long tid, ChatSessionType type, NoDisturbingRequest request, StringBuilder error) {
        return false;
    }

    @Override
    public boolean sendCustomizedMessage(Long senderId, int type, Long receiverId,
                                         String content, String sound,
                                         Map<String, Object> notification_config,
                                         Map<String, Object> push_config,
                                         StringBuilder error) {
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("sender_id", "" + senderId);
            reqParam.put("type", type);
            reqParam.put("receiver_id", "" + receiverId);
            reqParam.put("content", content);
            if (StringUtils.hasText(sound)) {
                reqParam.put("sound", sound);
            }
            if (notification_config != null) {
                reqParam.put("notification_config", notification_config);
            }
            if (push_config != null) {
                reqParam.put("push_config", push_config);
            }

            JSONObject jsonObject = YunXinHelper.exchange(SEND_SYSTEM_NOTIFY_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public boolean sendCustomizedMessages(Long senderId, List<Long> receiverIds,
                                          String content, String sound,
                                          Map<String, Object> notification_config,
                                          Map<String, Object> push_config,
                                          StringBuilder error) {
        try {
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("sender_id", "" + senderId);
            reqParam.put("receiver_ids", receiverIds.stream().map(x -> "" + x).collect(Collectors.toList()));
            reqParam.put("content", content);
            if (StringUtils.hasText(sound)) {
                reqParam.put("sound", sound);
            }
            if (notification_config != null) {
                reqParam.put("notification_config", notification_config);
            }
            if (push_config != null) {
                reqParam.put("push_config", push_config);
            }

            JSONObject jsonObject = YunXinHelper.exchange(BATCH_SEND_SYSTEM_NOTIFY_URL, HttpMethod.POST, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        yunXinProperties = applicationContext.getBean(YunXinProperties.class);
        ignite = applicationContext.getBean(Ignite.class);
    }

    private void throwExceptionByCode(Long code, JSONObject jsonObject) throws Exception {
        String errorInfo = ErrorCode.getErrorMessage(Constant.YUN_XIN_API_VERSION, code);
        if (StringUtils.hasText(errorInfo)) {
            if (code == 414L) {
                errorInfo = MessageFormat.format(errorInfo, jsonObject.get("msg"));
            }
            throw new Exception(errorInfo);
        } else {
            throw new Exception(MessageFormat.format("云信业务错误:{0}", "" + code));
        }
    }

    private boolean _updateManager(String url, HttpMethod method, Long operatorId, ChatSessionType type, List<Long> managers, StringBuilder error) {
        try {
            List<String> strList = new ArrayList<>();
            for (Long manager : managers) {
                strList.add("" + manager);
            }
            Map<String, Object> reqParam = new LinkedHashMap<>();
            reqParam.put("operator_id", "" + operatorId);
            /*群组类型。1：高级群；2：超大群。*/
            reqParam.put("team_type", Math.max(1, type.getType()));
            reqParam.put("managers", strList);

            JSONObject jsonObject = YunXinHelper.exchange(url, method, reqParam, yunXinProperties);
            Long code = jsonObject.getLong("code");
            if (code == 200L) {
                return true;
            }
            throwExceptionByCode(code, jsonObject);
        } catch (Exception ex) {
            error.append(ex.getMessage());
        }
        return false;
    }
}
